%{

using namespace std;
#include "commun.h"

int	xmlwrap(void);
void	xmlerror(Element **document, char **dtd, char const *msg);
int	xmllex(void);
extern	FILE *xmlin;
%}

%union {
    char	*s;
    ElementName *en;
    Attribute	*att;
    AttributeList	*att_l;
    Element	*el;
    ElList	*el_l;
    XMLChildren	*ch;
    NodeList	*nl;
}

//%name-prefix "xml"
%parse-param {Element **root}
%parse-param {char **dtd}

%token EQ SLASH CLOSE CLOSESPECIAL DOCTYPE
%token <s> ENCODING STRING DATA COMMENT IDENT NSIDENT
%token <en> NSSTART START STARTSPECIAL END NSEND
%type <s> declarations_opt declaration
%type <att> attribut
%type <att_l> attribut_opt
%type <el> xml_element
%type <ch> empty_or_content
%type <en> start
%type <nl> content_opt close_content_and_finish

%%

document
 : declarations_opt xml_element misc_seq_opt	{*root = $2; *dtd = $1;}
 ;
misc_seq_opt
 : misc_seq_opt comment
 |				/*empty*/
 ;
comment
 : COMMENT
 ;

declarations_opt
 : declaration {$$ = $1;}
 | {$$ = "";}                    /* pas de dtd, on renvoie une chaine vide */
 ;
 
declaration
: DOCTYPE IDENT IDENT STRING CLOSE 		{ $$ = $4;}
 ;

xml_element
 : start empty_or_content 			{$$ = new Element($1->second, $1->first, $2->second, $2->first); delete $1; delete $2;}
 ;
start
 : START					{$$ = $1;}
 | NSSTART					{$$ = $1;}
 ;
empty_or_content
: attribut_opt SLASH CLOSE			{ $$ = new XMLChildren(*$1,NodeList()); }
| attribut_opt close_content_and_finish CLOSE 	{ $$ = new XMLChildren(*$1,*$2); }
 ;
close_content_and_finish
: CLOSE content_opt finish 			{ $$ = $2; }
 ;
finish
: END
| NSEND
;

content_opt 
 : content_opt DATA				{ $$ = $1; $$->push_back(new Content($2));}
 | content_opt comment				/* ignoré */
 | content_opt xml_element      		{ $$ = $1; $$->push_back($2);}
 | /*empty*/					{ $$ = new NodeList();}
 ;
attribut_opt
 : attribut_opt attribut 			{ $$=$1; $$->push_back($2);}
 | /*empty*/ 					{ $$ = new AttributeList();}
 ;
attribut
 : IDENT EQ STRING 				{$$ = new Attribute(string($1), string($3)); free($1); free($3);}
 | NSIDENT EQ STRING				{$$ = new Attribute(string($1), string($3)); delete $1; delete $3;}
 ;
%%

int xmlwrap(void)
{
  return 1;
}

void xmlerror(Element** document, char **dtd, char const *msg)
{
  fprintf(stderr, "%s\n", msg);
}
